// TODO: CODE REVIEW & CLEANUP!
//
// ClientStatus.cs
//
// Implements ClientStatus and related types.
//

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using HomeUX.ClientControlSupport;

namespace HomeUX.Controls
{

/// <summary>
/// TODO
/// </summary>
///
[TemplatePart(Name = LayoutRootName, Type = typeof(Panel))]
[TemplatePart(Name = DateTextBlockName, Type = typeof(TextBlock))]
[TemplatePart(Name = TimeTextBlockName, Type = typeof(TextBlock))]
[TemplateVisualState(GroupName = BusyStatesName, Name = IdleStateName)]
[TemplateVisualState(GroupName = BusyStatesName, Name = BusyStateName)]
[TemplateVisualState(GroupName = SimulationStatesName, Name = SimulatedStateName)]
[TemplateVisualState(GroupName = SimulationStatesName, Name = NotSimulatedStateName)]
public class ClientStatus : Control, IControlHelperConnector
{
    const string LayoutRootName = "LayoutRoot";
    const string DateTextBlockName = "DateTextBlock";
    const string TimeTextBlockName = "TimeTextBlock";
    const string BusyStatesName = "BusyStates";
    const string IdleStateName = "Idle";
    const string BusyStateName = "Busy";
    const string SimulationStatesName = "SimulationStates";
    const string SimulatedStateName = "Simulated";
    const string NotSimulatedStateName = "NotSimulated";

    Panel _layoutRoot;
    TextBlock _timeTextBlock;
    TextBlock _dateTextBlock;

    public static readonly DependencyProperty DateFormatProperty =
        DependencyProperty.Register("DateFormat", typeof(string), typeof(ClientStatus), null);
    public static readonly DependencyProperty TimeFormatProperty =
        DependencyProperty.Register("TimeFormat", typeof(string), typeof(ClientStatus), null);
    public static readonly DependencyProperty IsBusyProperty =
        DependencyProperty.Register("IsBusy", typeof(bool), typeof(ClientStatus),
            new PropertyMetadata(ClientStatus.OnIsBusyPropertyChanged));
    public static readonly DependencyProperty IsSimulatedProperty =
        DependencyProperty.Register("IsSimulated", typeof(bool), typeof(ClientStatus),
            new PropertyMetadata(ClientStatus.OnIsSimulatedPropertyChanged));

    /// <summary>
    /// The number of minutes between the time currently displayed and <n>DateTime.MinValue</n>,
    /// or 0 if <r>UpdateDisplay</r> has not been called yet.
    /// </summary>
    long _displayedTotalMinutes;

    DispatcherTimer _timer = new DispatcherTimer()
    {
        Interval = TimeSpan.FromMilliseconds(200)
    };

    public string DateFormat
    {
        get
        {
            return (string)GetValue(DateFormatProperty);
        }
        set
        {
            SetValue(DateFormatProperty, value);
        }
    }

    public string TimeFormat
    {
        get
        {
            return (string)GetValue(TimeFormatProperty);
        }
        set
        {
            SetValue(TimeFormatProperty, value);
        }
    }

    public string CurrentDateString
    {
        get
        {
            return _dateTextBlock.Text;
        }
    }

    public string CurrentTimeString
    {
        get
        {
            return _timeTextBlock.Text;
        }
    }

    public bool IsBusy
    {
        get
        {
            return (bool)GetValue(IsBusyProperty);
        }
        set
        {
            SetValue(IsBusyProperty, value);
        }
    }

    public bool IsSimulated
    {
        get
        {
            return (bool)GetValue(IsSimulatedProperty);
        }
        set
        {
            SetValue(IsSimulatedProperty, value);
        }
    }

    public ClientStatus()
    {
        DefaultStyleKey = typeof(ClientStatus);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        ControlHelper.GetRequiredTemplateChild(this, LayoutRootName, out _layoutRoot);
        ControlHelper.GetRequiredTemplateChild(this, DateTextBlockName, out _dateTextBlock);
        ControlHelper.GetRequiredTemplateChild(this, TimeTextBlockName, out _timeTextBlock);

        // update the display now, and check frequently if the display needs updating
        UpdateDisplay();
        _timer.Tick += delegate
        {
            UpdateDisplay();
        };
        _timer.Start();
    }

    /// <summary>
    /// Updates the information displayed by this control as needed (i.e. if it's changed).
    /// </summary>
    ///
    void UpdateDisplay()
    {
        // set <now> to the current date/time
        DateTime now = DateTime.Now;

        // set <totalMinutes> to the number of minutes between DateTime.MinValue and <now>
        long totalMinutes = (long)Math.Floor((now - DateTime.MinValue).TotalMinutes);

        // if the displayed date/time needs to be updated, so so now
        if (_displayedTotalMinutes != totalMinutes)
        {
            try
            {
                _dateTextBlock.Text = now.ToString(DateFormat);
            }
            catch (FormatException)
            {
                _dateTextBlock.Text = String.Empty;
            }
            try
            {
                _timeTextBlock.Text = now.ToString(TimeFormat);
            }
            catch (FormatException)
            {
                _dateTextBlock.Text = String.Empty;
            }
            _displayedTotalMinutes = totalMinutes;
        }
    }

    static void OnIsBusyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (ClientStatus)d;
        bool isBusy = (bool)e.NewValue;
        VisualStateManager.GoToState(target, isBusy ? BusyStateName : IdleStateName, true);
    }

    static void OnIsSimulatedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = (ClientStatus)d;
        bool isSimulated = (bool)e.NewValue;
        VisualStateManager.GoToState(target,
			isSimulated ? SimulatedStateName : NotSimulatedStateName, true);
    }

    #region IControlHelperConnector Members

    Control IControlHelperConnector.GetControl()
    {
        return this;
    }

    DependencyObject IControlHelperConnector.GetTemplateChild(string childName)
    {
        return GetTemplateChild(childName);
    }

    #endregion
}

}

